import { DndContext, PointerSensor, useSensor } from '@dnd-kit/core'
import { restrictToHorizontalAxis, restrictToParentElement } from '@dnd-kit/modifiers'
import { arrayMove, horizontalListSortingStrategy, SortableContext, useSortable } from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import { ConfigProvider, Tabs } from 'antd'
import { cloneElement, useEffect, useState } from 'react'

import styles from './index.module.less'

const DraggableTabNode = ({ ...props }) => {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: props['data-node-key'],
  })
  const style = {
    ...props.style,
    transform: CSS.Translate.toString(transform),
    transition,
    zIndex: isDragging ? 2 : 1,
  }
  return cloneElement(props.children, {
    ref: setNodeRef,
    style,
    ...attributes,
    ...listeners,
  })
}

/**
 * @typedef {Object} OtherProps
 * @property {boolean} [draggable] 是否可拖拽
 */
/**
 * @typedef {import('antd/es/tabs').TabsProps & OtherProps} Props
 * @returns
 */

/**
 * @param {Props} props
 * @returns
 */
const AekTabs = props => {
  const { className, items: originalItems, draggable = false, ...other } = props

  const [items, setItems] = useState([])

  useEffect(() => {
    const addItems = originalItems.filter(originalItem => !items.find(item => item.key === originalItem.key))
    const existItems = items.filter(item => {
      const find = originalItems.find(originalItem => item.key === originalItem.key)
      if (find) {
        item.label = find.label
      }
      return !!find
    })
    setItems([...existItems, ...addItems])
  }, [JSON.stringify(originalItems)])

  const sensor = useSensor(PointerSensor, {
    activationConstraint: {
      distance: 10,
    },
  })

  const onDragEnd = ({ active, over }) => {
    if (active.id !== over?.id) {
      setItems(prev => {
        const activeIndex = prev.findIndex(i => i.key === active.id)
        const overIndex = prev.findIndex(i => i.key === over?.id)
        return arrayMove(prev, activeIndex, overIndex)
      })
    }
  }

  return (
    <ConfigProvider
      theme={{
        components: {
          Tabs: {
            horizontalMargin: 0,
          },
        },
      }}
    >
      <Tabs
        className={`${styles.aekTabs} ${className || ''}`}
        items={items}
        renderTabBar={
          draggable
            ? (tabBarProps, DefaultTabBar) => (
                <DndContext
                  sensors={[sensor]}
                  modifiers={[restrictToHorizontalAxis, restrictToParentElement]}
                  onDragEnd={onDragEnd}
                >
                  <SortableContext items={items.map(i => i.key)} strategy={horizontalListSortingStrategy}>
                    <DefaultTabBar {...tabBarProps}>
                      {node => (
                        <DraggableTabNode {...node.props} key={node.key}>
                          {node}
                        </DraggableTabNode>
                      )}
                    </DefaultTabBar>
                  </SortableContext>
                </DndContext>
              )
            : undefined
        }
        {...other}
      />
    </ConfigProvider>
  )
}

export default AekTabs
